#include "games/blackjackgame.h"

BlackJackGame::BlackJackGame(QWidget *parent, int difflvl) :
    BaseGame(parent, difflvl)
{
    // Setup first widgets
    bet_spinbox = new QSpinBox(this);
    dealer_cards_label = new QLabel("-", this);
    dealer_points_label = new QLabel("-", this);
    player_cards_label = new QLabel("-", this);
    player_points_label = new QLabel("-", this);
    hline = new QFrame(this);
    hline->setMaximumHeight(3);
    hline->setFrameShape(QFrame::HLine);
    hline->setFrameShadow(QFrame::Sunken);

    split_button = new QPushButton("Split!", this);
    insurance_button = new QPushButton("Insurance", this);
    double_button = new QPushButton("Double!", this);
    stay_button = new QPushButton("Stay!", this);
    hit_button = new QPushButton("Hit!", this);
    new_button = new QPushButton("Start!", this);

    hor_lay = new QHBoxLayout();

    // Add widgets to layouts
    lay->addWidget(dealer_cards_label,0,0);
    lay->addWidget(dealer_points_label,1,0);
    lay->addWidget(hline,2,0);
    lay->addWidget(player_cards_label,3,0);
    lay->addWidget(player_points_label,4,0);
    lay->addLayout(hor_lay,5,0);
    lay->addWidget(bet_spinbox,6,0);
    hor_lay->addWidget(insurance_button);
    hor_lay->addWidget(split_button);
    hor_lay->addWidget(double_button);
    hor_lay->addWidget(stay_button);
    hor_lay->addWidget(hit_button);
    hor_lay->addWidget(new_button);
    insurance_button->hide();
    split_button->hide();
    hit_button->hide();

    // Setup buttons and alignment and font and ranges
    double_button->setDisabled(true);
    stay_button->setDisabled(true);

    dealer_cards_label->setAlignment(Qt::AlignHCenter);
    dealer_points_label->setAlignment(Qt::AlignHCenter);
    player_cards_label->setAlignment(Qt::AlignHCenter);
    player_points_label->setAlignment(Qt::AlignHCenter);

    QFont font = dealer_points_label->font();
    font.setPointSize(72);
    font.setBold(true);
    dealer_points_label->setFont(font);
    player_points_label->setFont(font);

    bet_spinbox->setMinimum(difficulty_level * 10);
    bet_spinbox->setMaximum(difficulty_level * 100);
    bet_spinbox->setValue(difficulty_level * 10);

    // Connections
    connect(insurance_button, SIGNAL(clicked()), this, SLOT(onInsuranceButtonClicked()));
    connect(double_button, SIGNAL(clicked()), this, SLOT(onDoubleButtonClicked()));
    connect(split_button, SIGNAL(clicked()), this, SLOT(onSplitButtonClicked()));
    connect(stay_button, SIGNAL(clicked()), this, SLOT(onStayButtonClicked()));
    connect(hit_button, SIGNAL(clicked()), this, SLOT(onHitButtonClicked()));
    connect(new_button, SIGNAL(clicked()), this, SLOT(onNewButtonClicked()));

    // Setup variables
    one_played = false;

    points = 0;

    // Init deck
    int number_of_decks = 8;
    deck = QStringList();
    for(int i = 0; i < number_of_decks; i++) {
        for(int j = 0; j < 4; j++) {
            deck << "A" << "2" << "3" << "4" << "5" << "6" << "7" << "8" << "10" << "J" << "Q" << "K";
        }
    }
    cards_left = number_of_decks * 4 * 12;
}

void BlackJackGame::restart()
{
    new_button->setText("Again!");
    bet_spinbox->setEnabled(true);
    stay_button->setEnabled(true);
    hit_button->show();
    new_button->hide();

    player_cards = QStringList();
    dealer_cards = QStringList();
    player_points = QList<int>();
    dealer_points = QList<int>();
    player_points_label->setStyleSheet("color : black");
    dealer_points_label->setStyleSheet("color : black");

    dealer_cards_label->setText("-");
    dealer_points_label->setText("-");
    player_cards_label->setText("-");
    player_points_label->setText("-");

    dealer_blackjack = false;
    player_blackjack = false;

    startupTurns();
}

QString BlackJackGame::drawCard()
{
    cards_left--;
    return deck.takeAt(qrand() % cards_left);
}

QList<int> BlackJackGame::getValues(const QStringList & cards)
{
    QList<int> list;

    list.append(0);
    for(int i = 0; i < cards.length(); i++) {
        QString string = cards.at(i);
        if( string == "A" ) {
            int len = list.length();
            for(int j = 0; j < len; j++) {
                list[j] = list.at(j) + 1;
            }
            for(int j = 0; j < len; j++) {
                int value = list.at(j) + 10;
                bool skip = false;
                for(int k = 0; k < list.length(); k++) {
                    if( value == list.at(k) ) skip = true;
                }
                if( !skip ) list.append(value);
            }
        } else if ( string == "J" || string == "Q" ||  string == "K" ) {
            for(int j = 0; j < list.length(); j++) {
                list[j] = list.at(j) + 10;
            }
        } else {
            for(int j = 0; j < list.length(); j++) {
                list[j] = list.at(j) + string.toInt();
            }
        }
    }

    bool list_has_leq_21 = false;
    for(int i = 0; i < list.length(); i++) {
        if( list.at(i) <= 21 ) list_has_leq_21 = true;
    }
    int min = list.first();
    for(int i = list.length() - 1; i >= 0; i--) {
        if( list_has_leq_21 == true && list.at(i) > 21 ) list.takeAt(i);
        else if( list.at(i) < min ) min = list.at(i);
    }
    if( list_has_leq_21 == false ) {
        list = QList<int>();
        list << min;
    }

    return list;
}

bool BlackJackGame::checkOverflow(const QList<int> & list)
{
    if( list.at(0) <= 21 ) return false;
    return true;
}

bool BlackJackGame::checkBlackjack(const QStringList & list)
{
    QList<int> values = getValues(list);
    if( list.length() == 2 && values.length() == 2 && values.at(0) == 11 && values.at(1) == 21 ) return true;
    return false;
}

void BlackJackGame::dealerDrawCard()
{
    dealer_cards << drawCard();
    dealer_cards_label->setText(dealer_cards.join(" "));
    updatePoints();
}

void BlackJackGame::playerDrawCard()
{
    player_cards << drawCard();
    player_cards_label->setText(player_cards.join(" "));
    updatePoints();
}

void BlackJackGame::updatePoints()
{
    QString string = "";
    dealer_points = getValues(dealer_cards);
    for(int i = 0; i < dealer_points.length(); i++) {
        string += QString::number(dealer_points.at(i));
        if( i != dealer_points.length() - 1 ) string += "/";
    }
    dealer_points_label->setText(string);

    string = "";
    player_points = getValues(player_cards);
    for(int i = 0; i < player_points.length(); i++) {
        string += QString::number(player_points.at(i));
        if( i != player_points.length() - 1 ) string += "/";
    }
    player_points_label->setText(string);
}

void BlackJackGame::startupTurns()
{
    bet = bet_spinbox->value();
    bet_spinbox->setDisabled(true);
    playerDrawCard();
    playerDrawCard();
    double_button->setEnabled(true);
    if( player_cards.at(0) == player_cards.at(1) ) split_button->show();
    if( checkBlackjack(player_cards) ) {
        player_points_label->setStyleSheet("color : green");
        player_blackjack = true;
    }
    dealerDrawCard();
    if( dealer_cards.at(0) == "A") insurance_button->show();
}

void BlackJackGame::dealerTurns()
{
    dealerDrawCard();
    if( checkBlackjack(dealer_cards) ) {
        dealer_points_label->setStyleSheet("color : green");
        dealer_blackjack = true;
    }
    else while( dealer_points.at(0) < 17 ) {
        dealerDrawCard();
        if( checkOverflow(dealer_points) ) dealer_points_label->setStyleSheet("color : red");
    }

    endTurns();
}

void BlackJackGame::endTurns()
{
    stay_button->setEnabled(false);
    hit_button->hide();
    new_button->show();

    int dealer_best_points = dealer_points.at(0);
    for(int i = 0; i < dealer_points.length(); i++) {
        if( dealer_points.at(i) <= 21 && dealer_points.at(i) > dealer_best_points ) dealer_best_points = dealer_points.at(i);
    }
    int player_best_points = player_points.at(0);
    for(int i = 0; i < player_points.length(); i++) {
        if( player_points.at(i) <= 21 && player_points.at(i) > player_best_points ) player_best_points = player_points.at(i);
    }

    int winner;
    if( dealer_blackjack == true && player_blackjack == true ) winner = 0;
    else if( dealer_blackjack == true ) winner = -1;
    else if( player_blackjack == true ) winner = 1;
    else if( checkOverflow(player_points) ) winner = -1;
    else if( dealer_best_points > player_best_points && !checkOverflow(dealer_points) ) winner = -1;
    else if( dealer_best_points == player_best_points ) winner = 0;
    else if( dealer_best_points < player_best_points ) winner = 1;
    else winner = 1;

    if(winner == -1 || winner == 0) dealer_points_label->setStyleSheet("color : blue");
    if(winner == 1 || winner == 0) player_points_label->setStyleSheet("color : blue");
    if(winner == 1) emit pointsModification(bet);
    if(winner == -1) emit pointsModification(-bet);

    one_played = true;

    bet_spinbox->setEnabled(true);
}

void BlackJackGame::onDoubleButtonClicked()
{
    bet *= 2;
    double_button->setDisabled(true);
    playerDrawCard();
    if( checkOverflow(player_points) ) {
        player_points_label->setStyleSheet("color : red");
    }
    dealerTurns();
}

void BlackJackGame::onInsuranceButtonClicked()
{
    insurance_button->hide();
}

void BlackJackGame::onSplitButtonClicked()
{
    split_button->hide();
}

void BlackJackGame::onStayButtonClicked()
{
    split_button->hide();
    dealerTurns();
}

void BlackJackGame::onHitButtonClicked()
{
    split_button->hide();
    playerDrawCard();
    if( checkOverflow(player_points) ) {
        player_points_label->setStyleSheet("color : red");
        endTurns();
    }
}

void BlackJackGame::onNewButtonClicked()
{
    restart();
}
